﻿using JWT;
using JWT.Algorithms;
using JWT.Exceptions;
using JWT.Serializers;
using System;
using System.Collections.Generic;
using System.Configuration;

namespace XieCan.AspMVC.JWTAuth
{
    public class JWTHelper : XieCanBase
    {
        //自定义唯一凭证,通过此凭证来加密解密,不能泄露
        private static readonly string secret = ConfigurationManager.AppSettings["jwt:secret"] ?? "ThisIsASecret";

        private static readonly string algorithm = ConfigurationManager.AppSettings["jwt:algorithm"] ?? "SHA256";

        private static readonly string seconds = ConfigurationManager.AppSettings["jwt:seconds"] ?? "300";

        private static IJwtAlgorithm JwtAlgorithm
        {
            get
            {
                if (algorithm.Contains("384"))
                {
                    return new HMACSHA384Algorithm();
                }
                else if (algorithm.Contains("512"))
                {
                    return new HMACSHA512Algorithm();
                }
                else
                {
                    return new HMACSHA256Algorithm();
                }
            }
        }

        private static IDateTimeProvider DateTimeProvider => new UtcDateTimeProvider();

        public static IBase64UrlEncoder UrlEncoder => new JwtBase64UrlEncoder();

        public static IJsonSerializer JsonSerializer => new JsonNetSerializer();

        /// <summary>
        /// 生成Token字符串
        /// </summary>
        /// <param name="claims">需要追加的数据</param>
        /// <returns>token字符串</returns>
        public static OperateResult<string> Encoder(Dictionary<string, object> claims)
        {
            try
            {
                if (!double.TryParse(seconds, out double time))
                {
                    time = 300;
                }

                if (claims == null)
                    claims = new Dictionary<string, object>();

                //添加过期时间
                claims.Add("exp", DateTimeOffset.UtcNow.AddSeconds(time).ToUnixTimeSeconds());

                IJwtEncoder encoder = new JwtEncoder(JwtAlgorithm, JsonSerializer, UrlEncoder);
                return OperateResult<string>.Succeeded(encoder.Encode(claims, secret));
            }
            catch (Exception ex)
            {
                return OperateResult<string>.Failed(ex);
            }
        }

        /// <summary>
        /// 解密Token字符串
        /// </summary>
        /// <param name="token">token字符串</param>
        /// <returns>数字字典对象</returns>
        public static OperateResult<Dictionary<string, object>> Decoder(string token)
        {
            try
            {
                IJwtValidator validator = new JwtValidator(JsonSerializer, DateTimeProvider);
                IJwtDecoder decoder = new JwtDecoder(JsonSerializer, validator, UrlEncoder, JwtAlgorithm);
                var t = decoder.DecodeToObject<Dictionary<string, object>>(token, secret, verify: true);
                return OperateResult<Dictionary<string, object>>.Succeeded(t);
            }
            catch (TokenExpiredException)
            {
                return OperateResult<Dictionary<string, object>>.Failed("Token已经过期了");
            }
            catch (SignatureVerificationException)
            {
                return OperateResult<Dictionary<string, object>>.Failed("Token签名不正确");
            }
            catch (Exception ex)
            {
                return OperateResult<Dictionary<string, object>>.Failed(ex);
            }
        }
    }
}
